#!/bin/sh
# Copyright 2022 Stan Grishin (stangri@melmac.ca)
# shellcheck disable=SC2018,SC2019,SC2039,SC3043,SC3057,SC3060

# TechRef: https://openwrt.org/docs/techref/rpcd
# TESTS
# ubus -v list luci.pbr
# ubus -S call luci.pbr getInitList '{"name": "pbr" }'
# ubus -S call luci.pbr getInitStatus '{"name": "pbr" }'
# ubus -S call luci.pbr getPlatformSupport '{"name": "pbr" }'
# ubus -S call luci.pbr getGateways '{"name": "pbr" }'
# ubus -S call luci.pbr getInterfaces '{"name": "pbr" }'

readonly luciCompat='11'
readonly pbrFunctionsFile='/etc/init.d/pbr'
if [ -s "$pbrFunctionsFile" ]; then
# shellcheck source=../../../../../pbr/files/etc/init.d/pbr
	. "$pbrFunctionsFile"
else
	print_json_string 'error' "pbr init.d file ($pbrFunctionsFile) not found!"
	logger -t pbr 'error' "pbr init.d file ($pbrFunctionsFile) not found!"
fi

# compatibility with old luci app versions
is_running_iptables() { iptables -t mangle -L | grep -q PBR_PREROUTING >/dev/null 2>&1; }
is_running() { is_running_iptables || is_running_nft; }
check_ipset() { { [ -n "$ipset" ] && "$ipset" help hash:net; } >/dev/null 2>&1; }
check_agh_ipset() {
	check_ipset || return 1
	check_agh || return 1
	is_greater_or_equal "$($agh --version | sed 's|AdGuard Home, version v\(.*\)|\1|' | sed 's|-.*||')" '0.107.13'
}
check_dnsmasq_ipset() {
	local o;
	check_ipset || return 1
	check_dnsmasq || return 1
	o="$(dnsmasq -v 2>/dev/null)"
	! echo "$o" | grep -q 'no-ipset' && echo "$o" | grep -q 'ipset'
}

get_init_list() {
	local name
	name="$(basename "$1")"
	name="${name:-$packageName}" 
	json_init
	json_add_object "$packageName"
	json_add_boolean 'enabled' "$(is_enabled "$packageName")"
	if is_running "$packageName"; then
		json_add_boolean 'running' '1'
	else
		json_add_boolean 'running' '0'
	fi
	json_close_object
	json_dump
	json_cleanup
}

set_init_action() {
	local name action="$2" cmd
	name="$(basename "$1")"
	name="${name:-$packageName}" 
	if [ ! -f "/etc/init.d/$packageName" ]; then
		print_json_string 'error' 'Init script not found!'
		return
	fi
	case $action in
		enable)
			cmd="/etc/init.d/${name} ${action}"
			cmd="${cmd} && uci_set ${name} config enabled 1 && uci_commit $name"
		;;
		disable)
			cmd="/etc/init.d/${name} ${action}"
			cmd="${cmd} && uci_set ${name} config enabled 0 && uci_commit $name"
		;;
		start|stop|reload|restart)
			cmd="/etc/init.d/${name} ${action}"
		;;
	esac
	if [ -n "$cmd" ] && eval "$cmd" 1>/dev/null 2>&1; then
		print_json_bool 'result' '1'
	else
		print_json_bool 'result' '0'
	fi
}

get_init_status() {
	local name
	name="$(basename "$1")"
	name="${name:-$packageName}" 
	local gateways warnings errors
	gateways="$(ubus_get_status gateways | sed "s|\\\n|<br />|g;s|\(\\\033[^<]*\)|✓|g;")"
	warnings="$(ubus_get_status warnings)"
	errors="$(ubus_get_status errors)"
	json_init
	json_add_object  "$packageName"
	json_add_boolean 'enabled' "$(is_enabled "$packageName")"
	if is_running "$packageName"; then
		json_add_boolean 'running' '1'
	else
		json_add_boolean 'running' '0'
	fi
	if is_running_iptables "$packageName"; then
		json_add_boolean 'running_iptables' '1'
	else
		json_add_boolean 'running_iptables' '0'
	fi
	if is_running_nft "$packageName"; then
		json_add_boolean 'running_nft' '1'
	else
		json_add_boolean 'running_nft' '0'
	fi
	if is_running_nft_file "$packageName"; then
		json_add_boolean 'running_nft_file' '1'
	else
		json_add_boolean 'running_nft_file' '0'
	fi
	json_add_string 'version' "$PKG_VERSION"
	json_add_string 'gateways' "$gateways"
	json_add_array 'errors'
	if [ -n "$errors" ]; then
		while read -r line; do
			if str_contains "$line" ' '; then
				error_id="${line% *}"
				error_extra="${line#* }"
			else
				error_id="$line"
				unset error_extra
			fi
			json_add_object
			json_add_string 'id' "$error_id"
			json_add_string 'extra' "$error_extra"
			json_close_object
		done <<EOF
$(echo "$errors" | tr \# \\n)
EOF
	fi
	json_close_array
	json_add_array 'warnings'
	if [ -n "$warnings" ]; then
		while read -r line; do
			if str_contains "$line" ' '; then
				warning_id="${line% *}"
				warning_extra="${line#* }"
			else
				warning_id="$line"
				unset warning_extra
			fi
			json_add_object
			json_add_string 'id' "$warning_id"
			json_add_string 'extra' "$warning_extra"
			json_close_object
		done <<EOF
$(echo "$warnings" | tr \# \\n)
EOF
	fi
	if is_greater "${packageCompat:-0}" "${luciCompat:-0}"; then
		json_add_object
		json_add_string 'id' 'warningOutdatedLuciPackage'
		json_close_object
	elif is_greater "${luciCompat:-0}" "${packageCompat:-0}"; then
		json_add_object
		json_add_string 'id' 'warningOutdatedPrincipalPackage'
		json_close_object
	fi
	json_close_array
	json_close_object
	json_dump
	json_cleanup
}

get_platform_support() {
	local name
	name="$(basename "$1")"
	name="${name:-$packageName}" 
	json_init
	json_add_object "$packageName"
	if check_ipset; then
		json_add_boolean 'ipset_installed' '1'
	else
		json_add_boolean 'ipset_installed' '0'
	fi
	if check_nft; then
		json_add_boolean 'nft_installed' '1'
	else
		json_add_boolean 'nft_installed' '0'
	fi
	if check_agh; then
		json_add_boolean 'adguardhome_installed' '1'
	else
		json_add_boolean 'adguardhome_installed' '0'
	fi
	if check_dnsmasq; then
		json_add_boolean 'dnsmasq_installed' '1'
	else
		json_add_boolean 'dnsmasq_installed' '0'
	fi
	if check_unbound; then
		json_add_boolean 'unbound_installed' '1'
	else
		json_add_boolean 'unbound_installed' '0'
	fi
	if check_agh_ipset; then
		json_add_boolean 'adguardhome_ipset_support' '1'
	else
		json_add_boolean 'adguardhome_ipset_support' '0'
	fi
	if check_dnsmasq_ipset; then
		json_add_boolean 'dnsmasq_ipset_support' '1'
	else
		json_add_boolean 'dnsmasq_ipset_support' '0'
	fi
	if check_dnsmasq_nftset; then
		json_add_boolean 'dnsmasq_nftset_support' '1'
	else
		json_add_boolean 'dnsmasq_nftset_support' '0'
	fi
	json_close_object
	json_dump
	json_cleanup
}

# shellcheck disable=SC3037
get_gateways() {
	echo -en "{\"$packageName\":{\"gateways\":"
	ubus_get_gateways
	echo -en "}}"
}

get_supported_interfaces() {
	_build_ifaces_supported() { is_supported_interface "$1" && ! str_contains "$ifacesSupported" "$1" && ifacesSupported="${ifacesSupported}${1} "; }
	_find_firewall_wan_zone() { [ "$(uci_get 'firewall' "$1" 'name')" = "wan" ] && firewallWanZone="$1"; }
	local i
	local firewallWanZone
	local ifacesSupported
	local webui_show_ignore_target
	local ignored_interface supported_interface
	local wanIface4 wanIface6
	config_load "$packageName"
	config_get_bool webui_show_ignore_target 'config' 'webui_show_ignore_target' '0'
	config_get ignored_interface             'config' 'ignored_interface'
	config_get supported_interface           'config' 'supported_interface'
	config_get procd_wan_interface           'config' 'procd_wan_interface'  'wan'
	config_get procd_wan6_interface          'config' 'procd_wan6_interface' 'wan6'
	local i
	wanIface4="$procd_wan_interface"
	wanIface6="$procd_wan6_interface"
	config_load 'firewall'
	config_foreach _find_firewall_wan_zone 'zone'
	for i in $(uci_get 'firewall' "$firewallWanZone" 'network'); do
		is_supported_interface "$i" && ! str_contains "$ifacesSupported" "$1" && ifacesSupported="${ifacesSupported}${i} "
	done
	config_load 'network'
	config_foreach _build_ifaces_supported 'interface'
	is_tor_running && ifacesSupported="$ifacesSupported tor"
	for i in $supported_interface; do
		is_xray "$i" && ifacesSupported="$ifacesSupported $i"
	done
	[ "$webui_show_ignore_target" -eq '1' ] && ifacesSupported="$ifacesSupported ignore"
	json_init
	json_add_object "$packageName"
	json_add_array 'interfaces'
	for i in $ifacesSupported; do
		json_add_string '' "$i"
	done
	json_close_array
	json_close_object
	json_dump
	json_cleanup
}

case "$1" in
	list)
		json_init
		json_add_object "getGateways"
			json_add_string 'name' 'name'
		json_close_object
		json_add_object "getInitList"
			json_add_string 'name' 'name'
		json_close_object
		json_add_object "getInitStatus"
			json_add_string 'name' 'name'
		json_close_object
		json_add_object "getInterfaces"
			json_add_string 'name' 'name'
		json_close_object
		json_add_object "getPlatformSupport"
			json_add_string 'name' 'name'
		json_close_object
		json_add_object "setInitAction"
			json_add_string 'name' 'name'
			json_add_string 'action' 'action'
		json_close_object
		json_dump
		json_cleanup
		;;
	call)
		case "$2" in
			getGateways)
				read -r input
				json_load "$input"
				json_get_var name 'name'
				json_cleanup
				get_gateways "$packageName"
				;;
			getInitList)
				read -r input
				json_load "$input"
				json_get_var name 'name'
				json_cleanup
				get_init_list "$packageName"
				;;
			getInitStatus)
				read -r input
				json_load "$input"
				json_get_var name 'name'
				json_cleanup
				get_init_status "$packageName"
				;;
			getInterfaces)
				read -r input
				json_load "$input"
				json_get_var name 'name'
				json_cleanup
				get_supported_interfaces "$packageName"
				;;
			getPlatformSupport)
				read -r input
				json_load "$input"
				json_get_var name 'name'
				json_cleanup
				get_platform_support "$packageName"
				;;
			setInitAction)
				read -r input
				json_load "$input"
				json_get_var name 'name'
				json_get_var action 'action'
				json_cleanup
				set_init_action "$packageName" "$action"
				;;
		esac
	;;
esac
